import { ImageLayoutList } from "../util/v3pro.layout.list.util";
import { ImageLayout, Pixel } from "./v3pro.image.layout";
import { V3ProBinaryPixel } from "../util/v3pro.binary.pixel";
import { appConfig } from "../../../configs/env.config.load";
import {
  V3proSendBox,
  V3proSendBoxOutPort,
  V3proSendBoxScanBoard,
  V3proSendBoxScanBoardPanel,
} from "../../../api/v3pro-api/v3pro.api.response.model";

/**
 * 发送盒布局
 */
export class SendBoxLayout extends ImageLayout {
  constructor(sendbox: V3proSendBox) {
    super(sendbox.layout);
    this.id = sendbox.deviceInfo.id;
    this.name = sendbox.deviceInfo.name;
    this.addr = sendbox.deviceInfo.addr;
  }
  id: string;
  name: string;
  addr: string;
  outPorts = new ImageLayoutList<OutPortLayout>("ip");
  scanBoards = new ImageLayoutList<ScanBoardLayout>("id");

  addOutPort(outPort: OutPortLayout) {
    this.outPorts.add(outPort);
    return this;
  }

  addScanBoard(scanBoard: ScanBoardLayout) {
    this.scanBoards.add(scanBoard);
    return this;
  }

  toLayout() {
    return {
      id: this.id,
      name: this.name,
      addr: this.addr,
      ...this.toJSONObj(),
      outPorts: this.outPorts.map((outPort) => outPort.toLayout()),
      scanBoards: this.scanBoards.map((scanBoard) => scanBoard.toLayout()),
    };
  }
}

/**
 * 输出口布局
 */
export class OutPortLayout extends ImageLayout {
  constructor(
    outPort: V3proSendBoxOutPort,
    public belongSendBox: SendBoxLayout,
  ) {
    super(outPort);
    this.ip = outPort.originationIP;
    this.name = outPort.name;
    this.belongSendBox.addOutPort(this);
  }

  ip: string;
  name: string;
  scanBoards = new ImageLayoutList<ScanBoardLayout>("id");

  addScanBoard(scanBoard: ScanBoardLayout) {
    this.scanBoards.add(scanBoard);
    return this;
  }

  toLayout() {
    return {
      ip: this.ip,
      name: this.name,
      ...this.toJSONObj(),
      scanBoards: this.scanBoards.map((scanBoard) => scanBoard.toLayout()),
    };
  }
}

/**
 * 扫描板布局
 */
export class ScanBoardLayout extends ImageLayout {
  constructor(
    scanBoard: V3proSendBoxScanBoard,
    public belongSendBox: SendBoxLayout,
    public belongOutPort: OutPortLayout,
  ) {
    super(scanBoard.layout);
    this.id = scanBoard.deviceInfo.id;
    this.name = scanBoard.deviceInfo.name;
    this.addr = scanBoard.deviceInfo.addr;
    this.belongOutPort.addScanBoard(this);
    this.belongSendBox.addScanBoard(this);
    this.panelWidth = scanBoard.status?.panelConf?.width;
    this.panelHeight = scanBoard.status?.panelConf?.height;
  }

  id: string;
  name: string;
  addr: string;
  panelWidth: number;
  panelHeight: number;
  panels = new ImageLayoutList<PanelLayout>("index");

  addPanel(panel: PanelLayout) {
    this.panels.add(panel);
    return this;
  }

  toLayout() {
    return {
      id: this.id,
      name: this.name,
      addr: this.addr,
      panelWidth: this.panelWidth,
      panelHeight: this.panelHeight,
      ...this.toJSONObj(),
      panelCount: this.panels.length(),
    };
  }
}

/**
 * 面板布局
 */
export class PanelLayout extends ImageLayout {
  constructor(
    panel: V3proSendBoxScanBoardPanel,
    scanBoard: ScanBoardLayout,
    scanBoardInfo: V3proSendBoxScanBoard,
    public belongSendBox: SendBoxLayout,
    public belongOutPort: OutPortLayout,
    public belongScanBoard: ScanBoardLayout,
  ) {
    const [panelWidth, panelHeight] = [
      scanBoardInfo.status.panelConf.width,
      scanBoardInfo.status.panelConf.height,
    ];
    const columns = Math.round(scanBoardInfo.layout.width / panelWidth);
    super({
      width: panelWidth,
      height: panelHeight,
      x: scanBoard.x + (panel.index % columns) * panelWidth,
      y: scanBoard.y + Math.floor(panel.index / columns) * panelHeight,
    });
    this.index = panel.index;
    this.pixels = new V3ProBinaryPixel(panelWidth, panelHeight, this.x, this.y);
    this.belongScanBoard.addPanel(this);
  }
  index: number;
  pixels: V3ProBinaryPixel;

  isDeadPixelErr() {
    return this.getErrPixelRate() >= appConfig.v3pro.threshold.panelDeadPixedRate / 100;
  }

  getErrPixelCount() {
    return this.pixels.trueCount();
  }

  getErrPixelRate() {
    return this.pixels.trueCount() / this.pixels.size();
  }

  setErrPixel(pixel: Pixel) {
    if (this.inLayout(pixel)) {
      this.pixels.setTrue(pixel.x, pixel.y);
    }
  }

  toLayout() {
    return {
      index: this.index,
      ...this.toJSONObj(),
    };
  }
}
